Package org.python.pydev.outline

Source Code of org.python.pydev.outline.ParsedModel

/**
* Copyright (c) 2005-2011 by Appcelerator, Inc. All Rights Reserved.
* Licensed under the terms of the Eclipse Public License (EPL).
* Please see the license.txt included with this distribution for details.
* Any modifications to this file must keep this entire header intact.
*/
package org.python.pydev.outline;

import java.util.ArrayList;

import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.swt.widgets.Display;
import org.python.pydev.core.log.Log;
import org.python.pydev.editor.PyEdit;
import org.python.pydev.editor.model.IModelListener;
import org.python.pydev.parser.ErrorDescription;
import org.python.pydev.parser.jython.SimpleNode;
import org.python.pydev.parser.jython.ast.Attribute;
import org.python.pydev.parser.jython.ast.ClassDef;
import org.python.pydev.parser.jython.ast.FunctionDef;
import org.python.pydev.parser.jython.ast.Import;
import org.python.pydev.parser.jython.ast.ImportFrom;
import org.python.pydev.parser.jython.ast.aliasType;
import org.python.pydev.parser.visitors.scope.ASTEntryWithChildren;
import org.python.pydev.parser.visitors.scope.OutlineCreatorVisitor;


/**
* ParsedModel represents a python file, parsed for OutlineView display
* It takes PyParser, and converts it into a tree of ParsedItems
*/
public class ParsedModel implements IOutlineModel {

    PyEdit editor;
    PyOutlinePage outline;
    IModelListener modelListener;

    ParsedItem root = null; // A list of top nodes in this document. Used as a tree root

    /**
     * @param outline - If not null, view to notify when parser changes
     */
    public ParsedModel(PyOutlinePage outline, PyEdit editor) {
        this.editor = editor;
        this.outline = outline;

        // The notifications are only propagated to the outline page
        //
        // Tell parser that we want to know about all the changes
        // make sure that the changes are propagated on the main thread
        modelListener = new IModelListener() {

            public void modelChanged(final SimpleNode ast) {
                Display.getDefault().asyncExec(new Runnable() {
                    public void run() {
                        synchronized (this) {
                            OutlineCreatorVisitor visitor = OutlineCreatorVisitor.create(ast);
                            setRoot(new ParsedItem(visitor.getAll().toArray(new ASTEntryWithChildren[0]),
                                    ParsedModel.this.editor.getErrorDescription()));
                        }
                    }
                });
            }

            public void errorChanged(final ErrorDescription errorDesc) {
                Display.getDefault().asyncExec(new Runnable() {
                    public void run() {
                        synchronized (this) {
                            ParsedItem currRoot = getRoot();

                            ParsedItem newRoot;
                            if (currRoot != null) {
                                newRoot = new ParsedItem(currRoot.getAstChildrenEntries(), errorDesc);
                            } else {
                                newRoot = new ParsedItem(new ASTEntryWithChildren[0], errorDesc);
                            }
                            setRoot(newRoot);
                        }
                    }
                });
            }

        };

        OutlineCreatorVisitor visitor = OutlineCreatorVisitor.create(editor.getAST());
        root = new ParsedItem(visitor.getAll().toArray(new ASTEntryWithChildren[0]), editor.getErrorDescription());
        editor.addModelListener(modelListener);
    }

    public void dispose() {
        editor.removeModelListener(modelListener);
    }

    public ParsedItem getRoot() {
        return root;
    }

    // patchRootHelper makes oldItem just like the newItem
    //   the differnce between the two is
    private void patchRootHelper(ParsedItem oldItem, ParsedItem newItem, ArrayList<ParsedItem> itemsToRefresh,
            ArrayList<ParsedItem> itemsToUpdate) {

        ParsedItem[] newChildren = newItem.getChildren();
        ParsedItem[] oldChildren = oldItem.getChildren();

        // stuctural change, different number of children, can stop recursion
        if (newChildren.length != oldChildren.length) {

            //at this point, it'll recalculate the children...
            oldItem.updateTo(newItem);
            itemsToRefresh.add(oldItem);

        } else {

            // Number of children is the same, fix up all the children
            for (int i = 0; i < oldChildren.length; i++) {
                patchRootHelper(oldChildren[i], newChildren[i], itemsToRefresh, itemsToUpdate);
            }

            // see if the node needs redisplay
            String oldTitle = oldItem.toString();
            String newTitle = newItem.toString();
            if (!oldTitle.equals(newTitle)) {
                itemsToUpdate.add(oldItem);
            } else {
                ASTEntryWithChildren astThisOld = oldItem.getAstThis();
                ASTEntryWithChildren astThisNew = newItem.getAstThis();

                if (astThisOld != null && astThisNew != null && astThisOld.node != null && astThisNew.node != null
                        && astThisOld.node.getClass() != astThisNew.node.getClass()) {

                    itemsToUpdate.add(oldItem);
                }
            }

            oldItem.setAstThis(newItem.getAstThis());
            oldItem.setErrorDesc(newItem.getErrorDesc());
        }
    }

    /**
     * Replaces current root
     */
    public void setRoot(ParsedItem newRoot) {
        // We'll try to do the 'least flicker replace'
        // compare the two root structures, and tell outline what to refresh
        try {
            if (root != null) {
                ArrayList<ParsedItem> itemsToRefresh = new ArrayList<ParsedItem>();
                ArrayList<ParsedItem> itemsToUpdate = new ArrayList<ParsedItem>();
                patchRootHelper(root, newRoot, itemsToRefresh, itemsToUpdate);
                if (outline != null) {
                    if (outline.isDisposed()) {
                        return;
                    }

                    //to update
                    int itemsToUpdateSize = itemsToUpdate.size();
                    if (itemsToUpdateSize > 0) {
                        outline.updateItems(itemsToUpdate.toArray(new ParsedItem[itemsToUpdateSize]));
                    }

                    //to refresh
                    int itemsToRefreshSize = itemsToRefresh.size();
                    if (itemsToRefreshSize > 0) {
                        outline.refreshItems(itemsToRefresh.toArray(new ParsedItem[itemsToRefreshSize]));
                    }
                }

            } else {
                Log.log("No old model root?");
            }
        } catch (Throwable e) {
            Log.log(e);
        }
    }

    public SimpleNode[] getSelectionPosition(StructuredSelection sel) {
        if (sel.size() == 1) { // only sync the editing view if it is a single-selection
            Object firstElement = sel.getFirstElement();
            ASTEntryWithChildren p = ((ParsedItem) firstElement).getAstThis();
            if (p == null) {
                return null;
            }
            SimpleNode node = p.node;
            if (node instanceof ClassDef) {
                ClassDef def = (ClassDef) node;
                node = def.name;

            } else if (node instanceof Attribute) {
                Attribute attribute = (Attribute) node;
                node = attribute.attr;

            } else if (node instanceof FunctionDef) {
                FunctionDef def = (FunctionDef) node;
                node = def.name;

            } else if (node instanceof Import) {
                ArrayList<SimpleNode> ret = new ArrayList<SimpleNode>();
                Import importToken = (Import) node;
                for (int i = 0; i < importToken.names.length; i++) {
                    aliasType aliasType = importToken.names[i];

                    //as ...
                    if (aliasType.asname != null) {
                        ret.add(aliasType.asname);
                    }

                    ret.add(aliasType.name);
                }
                return ret.toArray(new SimpleNode[0]);

            } else if (node instanceof ImportFrom) {
                ArrayList<SimpleNode> ret = new ArrayList<SimpleNode>();
                ImportFrom importToken = (ImportFrom) node;
                boolean found = false;
                for (int i = 0; i < importToken.names.length; i++) {
                    found = true;
                    aliasType aliasType = importToken.names[i];

                    //as ...
                    if (aliasType.asname != null) {
                        ret.add(aliasType.asname);
                    }

                    ret.add(aliasType.name);
                }
                if (!found) {
                    ret.add(importToken.module);
                }
                return ret.toArray(new SimpleNode[0]);
            }
            return new SimpleNode[] { node };
        }
        return null;
    }

}
TOP

Related Classes of org.python.pydev.outline.ParsedModel

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.